﻿using UnityEngine;
using System.Collections;

namespace ProjectTW.Foliage
{
    /// <summary>
    /// An custom math class.
    /// </summary>
    public static class FoliageMathUtility
    {
        public static System.Random Random = new System.Random();
        
        public static float Distance(Vector2 a, Vector2 b)
        {
            return (a - b).sqrMagnitude;
        }

        public static float Distance(Vector3 a, Vector3 b)
        {
            return (a - b).sqrMagnitude;
        }
       
        public static bool CheckIfBetween(Vector3 checkVector, int boundsA, int boundsB)
        {
            return checkVector.x > boundsA && checkVector.x < boundsB &&
                   checkVector.y > boundsA && checkVector.y < boundsB;
        }

        public static float GetRndRange(this System.Random rnd, float min, float max)
        {
            if (rnd == null)
            {
                rnd = Random;
            }

            return (float) (min + rnd.NextDouble() * (max - min));
        }

        public static float GetHeightAtWorldPoint(float x, float z, Vector3 terrainSize, float[,] heights)
        {
            x = Mathf.Clamp(x, 0, terrainSize.x);
            z = Mathf.Clamp(z, 0, terrainSize.z);

            return heights[(int) x, (int) z];
        }

        public static Vector3 GetNormalAtWorldPoint(float x, float z, Vector3 terrainSize, Vector3[,] normals)
        {
            x = Mathf.Clamp(x, 0, terrainSize.x);
            z = Mathf.Clamp(z, 0, terrainSize.z);

            return normals[(int) x, (int) z];
        }

        public static bool isBitMasked(this int mask, int bit)
        {
            return (mask & (1 << bit)) > 0;
        }

        public static bool CheckMinMaxBounds(Vector2 min, Vector2 max, float offset, Vector2 position)
        {
            Vector2 offset2D = new Vector2(offset, offset);

            min -= offset2D;
            max += offset2D;

            return position.x > min.x && position.y > min.y                        // check pos is bigger than minimum value
                                      && position.x < max.x && position.y < max.y; // check pos is tinier than max value.
        }

        public static int iClamp(int x, int from, int to)
        {
            if (x < from)
            {
                return from;
            }

            if (x > to)
            {
                return to;
            }

            return x;
        }

        public static int iClampMin(int x, int from)
        {
            if (x < from)
            {
                return from;
            }

            return x;
        }

        public static int iClampMax(int x, int to)
        {
            if (x > to)
            {
                return to;
            }

            return x;
        }
    }

    public struct Vector2i
    {
        public int x;
        public int y;

        public Vector2i(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        public static Vector2i operator +(Vector2i a, Vector2i b)
        {
            return new Vector2i(a.x + b.x, a.y + b.y);
        }

        public static Vector2i operator -(Vector2i a, Vector2i b)
        {
            return new Vector2i(a.x - b.x, a.y - b.y);
        }

        public static Vector2i operator *(Vector2i a, Vector2i b)
        {
            return new Vector2i(a.x * b.x, a.y * b.y);
        }

        public static Vector2i operator /(Vector2i a, Vector2i b)
        {
            return new Vector2i(a.x / b.x, a.y / b.y);
        }

        public static bool operator ==(Vector2i a, Vector2i b)
        {
            return a.x == b.x && a.y == b.y;
        }

        public static bool operator !=(Vector2i a, Vector2i b)
        {
            return a.x != b.x || a.y != b.y;
        }

        public override bool Equals(object obj)
        {
            if (obj.GetType() != typeof(Vector2i))
            {
                return false;
            }

            Vector2i instance = (Vector2i) obj;

            return instance == this;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return string.Format("Foliage Vector2i : \nx: {0} \ny : {1}", x, y);
        }
    }

    public struct Vector2b
    {
        public byte x;
        public byte y;

        public Vector2b(byte x, byte y)
        {
            this.x = x;
            this.y = y;
        }
    }
}
